package com.matt.service.impl;

import com.matt.commons.exception.BusinessException;
import com.matt.domain.materials.*;
import com.matt.foundation.model.ErrorCode;
import com.matt.commons.page.PagerQuery;
import com.matt.foundation.vo.materiels.MaterielItemVO;
import com.matt.repository.materials.*;
import com.matt.service.MaterialsService;
import com.matt.service.remoteCall.SsoCallService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class MaterialsServiceImpl implements MaterialsService {

    @Autowired
    private MaterielRecordsRepository recordsRepository;

    @Autowired
    private MaterielRecordItemsRepository recordItemsRepository;

    @Autowired
    private MaterielsRepository materielsRepository;

    @Autowired
    private MaterielCategoryRepository categoryRepository;

    @Autowired
    private UserMaterielsRepository userMaterielsRepository;

//    @Autowired
//    private RedPointService redPointService;
    
    @Autowired
    private SsoCallService ssoCallService;
    @Override
    public Page<Materiels> list(String areaId, String cid, Boolean consumable, PagerQuery pagerQuery) {

        PageRequest pageRequest = PageRequest.of(pagerQuery.getPageNum(), pagerQuery.getPageSize());

        if(StringUtils.isEmpty(cid)){
            if(consumable == null){
                return  materielsRepository.findAllByAidAndDeletedOrderByCreatedDesc(areaId, false, pageRequest);
            }
            return  materielsRepository.findAllByAidAndConsumableAndDeletedOrderByCreatedDesc(areaId, consumable, false, pageRequest);
        }else{
            MaterielCategory c = categoryRepository.getOne(cid);
            if(consumable == null){
                return  materielsRepository.findAllByAidAndCategoryAndDeletedOrderByCreatedDesc(areaId, c, false, pageRequest);
            }
            return  materielsRepository.findAllByAidAndCategoryAndConsumableAndDeletedOrderByCreatedDesc(areaId, c, consumable, false, pageRequest);
        }
    }

    @Override
    public List<MaterielCategory> category(String areaId) {
        return categoryRepository.findAllByAreaIdOrAreaIdIsNullOrderBySortDesc(areaId);
    }

    @Override
    public MaterielCategory addCategory(String areaId, String name, int sort) {
        MaterielCategory c = categoryRepository.findFirstByAreaIdBothDefaultAndName(areaId, name);

        if(c != null){
            throw new BusinessException(ErrorCode.CATEGORY_ERROR, "分类已经存在");
        }

        c = new MaterielCategory();
        c.setAreaId(areaId);
        c.setName(name);
        c.setSort(sort);
        categoryRepository.save(c);

        return c;
    }

    @Override
    public Materiels add(String areaId, String id, String cid, String name, Integer count, boolean comsumable) {
        MaterielCategory c = categoryRepository.findFirstByAreaIdBothDefaultAndId(areaId, cid);

        if(c == null){
            throw new BusinessException(ErrorCode.CATEGORY_ERROR, "分类不存在");
        }

        if(count <= 0){
            throw new BusinessException(ErrorCode.ERROR, "数量错误");
        }

        //找到资产
        Materiels m = null;
        if(StringUtils.isBlank(id)) {
            m = materielsRepository.findFirstByAidAndCategoryAndNameAndDeleted(areaId, c, name, false);

            if(m != null){
                throw new BusinessException(ErrorCode.MATERIAL_NOT_EXIST, "同样分类下已经有这个名字的物资存在");
            }

            m = new Materiels();

            m.setStockCount(count);
            m.setAllCount(count);
            m.setAid(areaId);
            m.setCategory(c);
            m.setName(name);
            m.setConsumable(comsumable);

            materielsRepository.save(m);
        } else {
            m = materielsRepository.findFirstByAidAndId(areaId, id);

            if(m == null){
                throw new BusinessException(ErrorCode.MATERIAL_NOT_EXIST, "没有找到物资");
            }

            m.setCategory(c);
            m.setName(name);

            if(comsumable != m.getConsumable()){
                if(m.getConsumable() && m.getAllConsumed() > 0){
                    throw new BusinessException(ErrorCode.CHECK_STATUS_ERROR, "物资已经被领用一些数量, 无法转成借用型。" );
                }else if(!m.getConsumable() && m.getAllBorrow() > 0){
                    throw new BusinessException(ErrorCode.CHECK_STATUS_ERROR, "物资尚有数量未归还, 无法转成领用型。" );
                }

                m.setConsumable(comsumable);
                //调整库存
                m.setAllCount(count);
                m.setStockCount(count);
            }else {
                if(comsumable){
                    if(count < (m.getAllConsumed() + m.getLoss())){
                        throw new BusinessException(ErrorCode.CHECK_STATUS_ERROR, "总数量不得小于领用数量");
                    }
                    m.setAllCount(count);
                    m.setStockCount(count - m.getAllConsumed() - m.getLoss());
                }else{
                    if(count < (m.getAllBorrow() + m.getLoss())){
                        throw new BusinessException(ErrorCode.CHECK_STATUS_ERROR, "总数量不得小于借出数量");
                    }
                    m.setAllCount(count);
                    m.setStockCount(count - m.getAllConsumed() - m.getLoss());
                }
            }
        }

        if (m!= null){
            materielsRepository.save(m);
        }

        return m;
    }

    public Integer delete(String areaId, String id){
        Materiels m = materielsRepository.findFirstByAidAndId(areaId, id);

        if(m == null){
            throw new BusinessException(ErrorCode.MATERIAL_NOT_EXIST, "没有找到物资");
        }

        if(m.getAllBorrow() > 0){
            throw new BusinessException(ErrorCode.CHECK_STATUS_ERROR, "尚有未归还物资");
        }

        m.setDeleted(true);

        materielsRepository.save(m);

        return 1;
    }

    @Override
    public Page<MaterielRecords> records(String staffId,String areaId, Integer type, String name, String operatorName, String startDate, String endDate, PagerQuery pagerQuery) {

        PageRequest pageRequest = PageRequest.of(pagerQuery.getPageNum(), pagerQuery.getPageSize());

        Specification<MaterielRecords> specification = new Specification<MaterielRecords>() {
            @Override
            public Predicate toPredicate(Root<MaterielRecords> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("aid"), areaId)));
                predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("actType"), type)));

                if(StringUtils.isNotEmpty(name)){
                    predicates.add(criteriaBuilder.and(criteriaBuilder.like(root.get("linkName"), "%" + name + "%")));
                }
                if(StringUtils.isNotEmpty(operatorName)){
                    predicates.add(criteriaBuilder.and(criteriaBuilder.like(root.get("operatorName"), "%" + operatorName + "%")));
                }
                if(StringUtils.isNotEmpty(startDate)){
                    predicates.add(criteriaBuilder.and(criteriaBuilder.greaterThanOrEqualTo(root.get("date"), startDate)));
                }
                if(StringUtils.isNotEmpty(endDate)){
                    predicates.add(criteriaBuilder.and(criteriaBuilder.lessThanOrEqualTo(root.get("date"), startDate)));
                }

                query.where(predicates.toArray(new Predicate[predicates.size()]));

                query.orderBy(criteriaBuilder.desc(root.get("created")));

                return query.getRestriction();
            }
        };

        return recordsRepository.findAll(specification,pageRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MaterielRecords addRecord(String areaId, String operatorName, String operatorId,
                                     String uid, String uname,
                                     Integer type, Date date, String remark, List<MaterielItemVO> items) {
        //创建操作记录
        MaterielRecords record = new MaterielRecords();
        record.setActType(type);
        record.setAid(areaId);
        record.setOperatorName(operatorName);
        record.setOperatorId(operatorId);
        record.setLinkId(uid);
        record.setLinkName(uname);
        record.setDate(date);
        record.setRemark(remark);

        recordsRepository.save(record);

        for(MaterielItemVO vo : items){
            parseMaterielItem(record, vo, type, uid, uname);
        }
        String title="";
        String content="";
//        if(type==1){
//            title=operatorName + "于" + date + "增加物资借出记录";
//            redPointService.addRemindRedNumByType(areaId, null,null, RedPointConstant.RED_POINT_MATERIALS_LEND, 1, title, content,record.getId(),RoleCodeConstant.ROLE_CODE_LEADER);
//        }else if(type == 2){
//            //redPointService.delRemindRedNumByType(areaId,null, RedPointConstant.RED_POINT_MATERIALS_RETURNED, 1, record.getId(),RoleCodeConstant.ROLE_CODE_LEADER);
//            title=operatorName+"于"+date+"增加物资归还记录";
//            redPointService.addRemindRedNumByType(areaId, null,null, RedPointConstant.RED_POINT_MATERIALS_RETURNED, 1, title, content,record.getId(),RoleCodeConstant.ROLE_CODE_LEADER);
//        }else if(type == 3){
//            //redPointService.delRemindRedNumByType(areaId,null, RedPointConstant.RED_POINT_MATERIALS_RETURNED, 1, record.getId(),RoleCodeConstant.ROLE_CODE_LEADER);
//            title=operatorName+"于"+date+"增加物资领用记录";
//            redPointService.addRemindRedNumByType(areaId, null,null, RedPointConstant.RED_POINT_MATERIALS_COMSUMED, 1, title, content,record.getId(),RoleCodeConstant.ROLE_CODE_LEADER);
//        }


        return record;
    }

    private void parseMaterielItem(MaterielRecords record, MaterielItemVO vo, int type, String uid, String uname){
        Materiels materiel = materielsRepository.getOne(vo.getMid());
        if(materiel == null){
            throw  new BusinessException(ErrorCode.ERROR, "资产不存在");
        }

        if(materiel.getConsumable() && (type == 1 || type == 2)){
            throw new BusinessException(ErrorCode.ERROR, "消耗型物品无法借出或者归还");
        }

        if(type == 1 && materiel.getStockCount() < vo.getCount()){
            // 借出
            throw new BusinessException(ErrorCode.ERROR, "库存不足");
        }else if( type == 2 && materiel.getAllBorrow() < vo.getCount()){
            //归还
            throw new BusinessException(ErrorCode.ERROR, "总数量错误无法归还");
        }else if(type == 3 ) {
            // 领用
            if(!materiel.getConsumable()){
                throw new BusinessException(ErrorCode.ERROR, "非可领取物资");
            }else if(materiel.getStockCount() < vo.getCount()) {
                throw new BusinessException(ErrorCode.ERROR, "库存不足");
            }
        }

        //找到用户资产关联记录
        UserMateriels userMateriel = userMaterielsRepository.findFirstByAidAndUidAndMateriels(record.getAid(), uid, materiel);
        if(userMateriel == null){
            userMateriel = new UserMateriels();
            userMateriel.setAid(record.getAid());
            userMateriel.setMateriels(materiel);
            userMateriel.setUid(uid);
            userMateriel.setUname(uname);
            userMateriel.setCount(0);
            userMaterielsRepository.save(userMateriel);
        }

        if(type == 2 && userMateriel.getCount() < vo.getCount()){
            throw new BusinessException(ErrorCode.ERROR, "数量错误无法归还");
        }

        if( type == 1 /*借出*/) {
            userMateriel.setCount(userMateriel.getCount() + vo.getCount());
            userMateriel.setType(0); //借取
            materiel.setAllBorrow(materiel.getAllBorrow() + vo.getCount());
            materiel.setStockCount(materiel.getStockCount() - vo.getCount());
        }else if(type == 2) /*归还*/{
            userMateriel.setCount(userMateriel.getCount() - vo.getCount());
            materiel.setAllBorrow(materiel.getAllBorrow() - vo.getCount());
            materiel.setStockCount(materiel.getStockCount() + vo.getCount());
        }else if(type == 3) /*领用*/{
            userMateriel.setCount(userMateriel.getCount() + vo.getCount());
            userMateriel.setType(1); //领取
            materiel.setAllConsumed(materiel.getAllConsumed() + vo.getCount());
            materiel.setStockCount(materiel.getStockCount() - vo.getCount());
        }else{
            throw  new BusinessException(ErrorCode.ERROR, "不支持的type");
        }

        if( materiel.getStockCount() + materiel.getAllConsumed() > materiel.getAllCount() ||
        materiel.getStockCount() + materiel.getAllBorrow() > materiel.getAllCount() || materiel.getStockCount() < 0
                || materiel.getAllBorrow() < 0 || materiel.getAllCount() < 0 || userMateriel.getCount() < 0){
            throw new BusinessException(ErrorCode.ERROR, "数量错误");
        }

        userMaterielsRepository.save(userMateriel);
        materielsRepository.save(materiel);

        MaterielRecordItems item = new MaterielRecordItems();
        item.setCount(vo.getCount());
        item.setMaterielRecords(record);
        item.setMateriels(materiel);

        //
        recordItemsRepository.save(item);
    }

    @Override
    public List<UserMateriels> borrow(String areaId, String uid) {

        if(StringUtils.isEmpty(uid)) {
            return userMaterielsRepository.findAllByAidAndCountGreaterThanAndTypeOrderByCreatedDesc(areaId, 0, 0);
        }

        return userMaterielsRepository.findAllByAidAndUidAndCountGreaterThanAndTypeOrderByCreatedDesc(areaId, uid, 0, 0);
    }
}
